package cn.lili.modules.lucene;

import cn.lili.cache.Cache;
import cn.lili.cache.CachePrefix;
import cn.lili.modules.goods.entity.dos.Goods;
import cn.lili.modules.goods.service.GoodsService;
import cn.lili.modules.search.entity.dos.EsGoodsIndex;
import cn.lili.modules.search.service.EsGoodsIndexService;
import lombok.extern.slf4j.Slf4j;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.StringField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexNotFoundException;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.store.Directory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.FileSystemUtils;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @Author Sylow
 * @Description 安全索引访问
 * @Date: Created in 15:38 2025/6/23
 */
@Slf4j
@Service
public class OnDemandIndexInitializer {

    @Value("${lili.system.lucene.path}")
    private String indexPath;

    private final Lock initLock = new ReentrantLock();
    private final IndexStateManager stateManager;
    private final IndexWriterFactory writerFactory;
    private final GoodsService goodsService;
    private final Directory directory; // 添加 Directory 引用

    @Autowired
    private EsGoodsIndexService esGoodsIndexService;

    @Autowired
    private Cache<Object> cache;

    @Autowired
    public OnDemandIndexInitializer(IndexStateManager stateManager,
                                    IndexWriterFactory writerFactory,
                                    GoodsService goodsService, Directory directory) {
        this.stateManager = stateManager;
        this.writerFactory = writerFactory;
        this.goodsService = goodsService;
        this.directory = directory;
    }

    /**
     * 确保索引已初始化
     */
    public void ensureInitialized() {
        if (stateManager.getCurrentState() == IndexState.READY) {
            return;
        }

        // 避免多个线程同时初始化
        if (!initLock.tryLock()) {
            // 如果锁已被占用，等待初始化完成
            awaitInitialization();
            return;
        }

        try {
            // 再次检查状态，防止其他线程已完成初始化
            if (stateManager.getCurrentState() != IndexState.READY) {
                initializeIndex();
            }
        } finally {
            initLock.unlock();
        }
    }

    /**
     * 强制重建索引
     */
    public void forceRebuild() {
        lockAndExecute(() -> {
            stateManager.transition(IndexState.READY, IndexState.REBUILDING);
            List<EsGoodsIndex> esGoodsIndices = esGoodsIndexService.getEsGoodsList();
            if (esGoodsIndices.isEmpty()) {
                log.warn("没有商品数据，创建空索引");
                createFallbackIndex();
            } else {
                log.info("开始全量重建索引，商品数量: {}", esGoodsIndices.size());
            }
            fullRebuild(esGoodsIndices);
            stateManager.transition(IndexState.REBUILDING, IndexState.READY);
            stateManager.recordRebuild();
        });
    }

    private void initializeIndex() {
        try {
            stateManager.forceState(IndexState.INITIALIZING);

            // 确保索引目录存在
            ensureIndexDirectoryExists();

            // 检查索引是否真正存在（有内容）
            boolean indexExists = isIndexExists();

            // 检查是否有有效的重建记录
            //boolean hasValidRebuildRecord = stateManager.getLastRebuildTimestamp() > 0;

            if (indexExists) {
                log.info("检测到有效索引和重建记录，尝试增量更新");
                incrementalUpdate();
            } else {
                if (indexExists) {
                    log.warn("索引存在但无重建记录，执行全量重建以确保数据完整性");
                } else {
                    log.info("未检测到有效索引，执行全量重建");
                }
                List<EsGoodsIndex> esGoodsIndices = esGoodsIndexService.getEsGoodsList();
                if (esGoodsIndices.isEmpty()) {
                    log.warn("没有商品数据，创建空索引");
                    createFallbackIndex();
                } else {
                    log.info("开始全量重建索引，商品数量: {}", esGoodsIndices.size());
                }
                fullRebuild(esGoodsIndices);
            }

            stateManager.transition(IndexState.INITIALIZING, IndexState.READY);
            stateManager.recordRebuild();
            log.info("索引初始化成功");
        } catch (Exception e) {
            handleInitializationError(e);
        }
    }

    private void ensureIndexDirectoryExists() throws IOException {
        Path path = Paths.get(indexPath);
        if (!Files.exists(path)) {
            Files.createDirectories(path);
            log.info("创建索引目录: {}", path);
        }
    }

    /**
     * 检查索引是否存在
     */
    private boolean isIndexExists() {
        try (DirectoryReader reader = DirectoryReader.open(directory)) {
            // 真正的索引存在应该有文档或段文件
            return reader.numDocs() > 0;
        } catch (IndexNotFoundException e) {
            return false;
        } catch (IOException e) {
            log.error("检查索引是否存在时出错", e);
            return false;
        }
    }

    /**
     * 处理初始化错误
     */
    private void handleInitializationError(Throwable error) {
        log.error("索引初始化失败", error);
        stateManager.forceState(IndexState.ERROR);

        // 清理可能损坏的索引
        cleanupCorruptedIndex();

        // 发送警报通知
        sendAlert("索引初始化失败: " + error.getMessage());

        // 尝试创建空索引作为回退
        createFallbackIndex();
    }

    /**
     * 清理损坏的索引
     */
    private void cleanupCorruptedIndex() {
        try {
            Path path = Paths.get(indexPath);
            if (Files.exists(path)) {
                log.warn("清理可能损坏的索引目录: {}", indexPath);
                FileSystemUtils.deleteRecursively(path);
                Files.createDirectories(path);
                log.info("索引目录已清理");
            }
        } catch (IOException e) {
            log.error("清理索引目录失败", e);
        }
    }

    /**
     * 创建回退索引
     */
    private void createFallbackIndex() {
        try {
            log.info("尝试创建空索引作为回退方案");
            try (IndexWriter writer = writerFactory.createWriter()) {
                writer.commit();
            }
            log.info("空索引创建成功");
        } catch (Exception e) {
            log.error("创建回退索引失败", e);
        }
    }

    /**
     * 全量重建索引
     */
    private void fullRebuild(List<EsGoodsIndex> esGoodsIndices ) {
        Instant start = Instant.now();
        log.info("开始全量重建索引...");

        try (IndexWriter writer = writerFactory.createWriter()) {
            // 删除所有现有文档
            writer.deleteAll();

            // 批量添加文档
            List<Document> documents = new ArrayList<>();
            esGoodsIndices.forEach(esGoodsIndex -> {
                Document document = LuceneUtil.convertToDocument(esGoodsIndex);
                documents.add(document);
            });
            writer.addDocuments(documents);
            writer.commit();

            Duration duration = Duration.between(start, Instant.now());
            log.info("索引重建完成! 共索引 {} 条商品, 耗时 {} 秒",
                    documents.size(), duration.getSeconds());
            cache.put(CachePrefix.INIT_INDEX_PROCESS.getPrefix(), "索引重建完成! 共索引 "  + documents.size() +" 条商品, 耗时 " + duration.getSeconds() + " 秒");
        } catch (Exception e) {
            e.printStackTrace();
            handleInitializationError(e);
        }

        //validateIndexAfterRebuild();
    }

    /**
     * 增量更新索引
     */
    private void incrementalUpdate() {
//        Instant start = Instant.now();
//        log.info("开始增量更新索引...");
//
//        try (IndexWriter writer = writerFactory.createWriter()) {
//            // 获取上次重建时间
//            long lastRebuildTime = stateManager.getLastRebuildTimestamp();
//
//            // 查询变更商品
//            List<Goods> updatedGoods = goodsRepository.findModifiedSince(lastRebuildTime);
//
//            // 处理更新
//            for (Goods goods : updatedGoods) {
//                Term term = new Term("id", goods.getId());
//                Document doc = convertToDocument(goods);
//                writer.updateDocument(term, doc);
//            }
//
//            // 提交更改
//            writer.commit();
//
//            // 记录性能指标
//            Duration duration = Duration.between(start, Instant.now());
//            log.info("增量更新完成! 更新 {} 条商品, 耗时 {} 毫秒",
//                    updatedGoods.size(), duration.toMillis());
//        } catch (Exception e) {
//            throw new IndexInitializationException("增量更新失败", e);
//        }
    }

    /**
     * 等待初始化完成
     */
    private void awaitInitialization() {
        final int maxWaitSeconds = 60;
        final int checkIntervalMs = 500;

        int attempts = 0;
        int maxAttempts = maxWaitSeconds * 1000 / checkIntervalMs;

        log.debug("等待索引初始化完成...");

        while (stateManager.getCurrentState() != IndexState.READY && attempts < maxAttempts) {
            try {
                TimeUnit.MILLISECONDS.sleep(checkIntervalMs);
                attempts++;
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            }
        }

        if (stateManager.getCurrentState() != IndexState.READY) {
            if (stateManager.getCurrentState() == IndexState.ERROR) {
                throw new IndexInitializationException("索引初始化失败");
            } else {
                throw new IndexInitializationException("索引初始化超时");
            }
        }
    }

    /**
     * 发送警报通知
     */
    private void sendAlert(String message) {
        // 实现警报发送逻辑，例如:
        // - 发送邮件
        // - 发送Slack通知
        // - 调用监控系统API
        log.warn("ALERT: {}", message);
    }

    /**
     * 加锁执行操作
     */
    private void lockAndExecute(Runnable action) {
        if (!initLock.tryLock()) {
            throw new RuntimeException("索引操作冲突，请稍后重试");
        }

        try {
            action.run();
        } finally {
            initLock.unlock();
        }
    }

    /**
     * 商品转文档的转换逻辑
     */
    private Document convertToDocument(Goods goods) {
        // 实现转换逻辑
        Document document = new Document();
        // 例如:
         document.add(new StringField("goodsName", goods.getGoodsName(), Field.Store.YES));
        return document;
    }

    private void validateIndexAfterRebuild() {
        try (DirectoryReader reader = DirectoryReader.open(directory)) {
            long docCount = reader.numDocs();
            if (docCount == 0) {
                log.error("重建后索引文档数为0，可能存在问题");
                throw new IndexInitializationException("重建后索引为空");
            }

            log.info("索引验证通过，文档数: {}", docCount);
        } catch (Exception e) {
            log.error("索引验证失败", e);
            throw new IndexInitializationException("索引验证失败");
        }
    }

    /**
     * 自定义异常类
     */
    public static class IndexInitializationException extends RuntimeException {
        public IndexInitializationException(String message) {
            super(message);
        }

        public IndexInitializationException(String message, Throwable cause) {
            super(message, cause);
        }
    }
}